import java.util.concurrent.TimeUnit;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class LatteScriptingWorld {

    public static void main(String[] args) throws Exception {

        ScriptEngineManager scriptEngineMgr = new ScriptEngineManager();
        ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("Latte");

        if (jsEngine == null) {
            System.err.println("No script engine found for Latte");
            System.exit(1);
        }

        System.out.println("Calling invokeHelloScript...");
        invokeHelloScript(jsEngine);
        TimeUnit.SECONDS.sleep(2);

        System.out.println("\nCalling defineScriptFunction...");
        defineScriptFunction(jsEngine);

        System.out.println("\nCalling invokeScriptFunctionFromEngine...");
        invokeScriptFunctionFromEngine(jsEngine);

        System.out.println("\nCalling invokeScriptFunctionFromJava...");
        invokeScriptFunctionFromJava(jsEngine);

        System.out.println("\nCalling invokeJavaFromScriptFunction...");
        invokeJavaFromScriptFunction(jsEngine);
    }

    //调用脚本语言
    private static void invokeHelloScript(ScriptEngine jsEngine) throws ScriptException {
        jsEngine.eval("println('Hello from Latte')");
    }

    //定义脚本语言
    private static void defineScriptFunction(ScriptEngine engine) throws ScriptException {
        // Define a function in the script engine
        engine.eval("fun  sayHello(name) {" + "    println('Hello, ' + name); return 123" + "}");
    }

    //调用脚本语言
    private static void invokeScriptFunctionFromEngine(ScriptEngine engine) throws ScriptException {
        Object obj = engine.eval("sayHello('World!')");
        System.out.println("sayHello return:" + obj);
    }

    //java调用脚本语言
    private static void invokeScriptFunctionFromJava(ScriptEngine engine)
            throws ScriptException, NoSuchMethodException {
        if (engine instanceof Invocable) {
            Invocable invocableEngine = (Invocable) engine;
            Object obj = invocableEngine.invokeFunction("sayHello", "from Java");
            System.out.println("sayHello return:" + obj);
        }
        else {
            System.err.println("engine don't support invokeScriptFunctionFromJava");
        }
    }

    //脚本语言中调用java方法
    private static void invokeJavaFromScriptFunction(ScriptEngine engine) throws ScriptException {
        engine.put("helloScriptingWorld", new LatteScriptingWorld());
        engine.eval("println('Invoking getHelloReply method from Script...');"
                + "var msg = helloScriptingWorld.getHelloReply('Latte');" + "println('Java returned:' + msg);"
                + "msg = helloScriptingWorld.getHelloReplyByStatic('Latte');"
                + "println('Java returned:' + msg);");
    }

    /** Method invoked from the above script to return a string. */
    public String getHelloReply(String name) {
        return "Java method getHelloReply says, 'Hello, " + name + "'";
    }

    /** Method invoked from the above script to return a string. */
    public static String getHelloReplyByStatic(String name) {
        return "Java method getHelloReplyByStatic says, 'Hello, " + name + "'";
    }
}
